package com.greatwqs.wmall.gateway.support;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;

import jakarta.annotation.PostConstruct;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 路径检查，排除不需要登录的路径
 *
 * @author wang-qingsong
 * @since 2025/03/22
 */
@Component
public class PathCheckService {

    private static final Logger log = LoggerFactory.getLogger(PathCheckService.class);

    private static final String EXCLUDE_PATHS_KEY = "gateway.auth.exclude-paths";
    private static final String DEFAULT_EXCLUDE_PATHS = "/api/wmall/user/login";

    private final Config apolloConfig = ConfigService.getAppConfig();
    private final PathMatcher pathMatcher = new AntPathMatcher();
    private final CopyOnWriteArrayList<String> excludePaths = new CopyOnWriteArrayList<>();

    @PostConstruct
    public void init() {
        refreshPaths();
        apolloConfig.addChangeListener(changeEvent -> {
            if (changeEvent.isChanged(EXCLUDE_PATHS_KEY)) {
                refreshPaths();
            }
        });
    }

    public boolean shouldExclude(String requestPath) {
        return excludePaths.stream()
                .anyMatch(pattern -> pathMatcher.match(pattern, requestPath));
    }

    private void refreshPaths() {
        String configValue = apolloConfig.getProperty(EXCLUDE_PATHS_KEY, DEFAULT_EXCLUDE_PATHS);
        List<String> newPaths = parsePaths(configValue);
        excludePaths.clear();
        excludePaths.addAll(newPaths);
        log.info("Updated exclude paths: {}", newPaths);
    }

    private List<String> parsePaths(String configValue) {
        if (configValue == null || configValue.isEmpty()) {
            return Collections.emptyList();
        }
        return Arrays.stream(configValue.split(","))
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .toList();
    }
}